{ status : prototype }
unit hadeobject;

{$mode objfpc}{$H+}

interface

uses
  Classes,
  SysUtils,
  hadebasevisitor,
  hadeoid,
  contnrs,
  hadecriteria;

type
  THadeColInfo = (ptkPK,
    ptkFK,
    ptkUnique,
    ptkReadOnly,
    ptkWriteOnly
    );

  //taken from tiOPF but we move here
  THadeObjectState =
    (
    posEmpty,//0 The object has been created, but not filled with data from the DB
    posPK,//1 The object has been created, but only it's primary key has been read
    posCreate,//2 The object has been created and populated with data and must be saved to the DB
    posUpdate,//3 The object has been changed, the DB must be updated
    posDelete,//4 The object has been deleted, it must be deleted from the DB
    posDeleted,//5 The object was marked for deletion, and has been deleted in the database
    posClean//6 The object is 'Clean' no DB update necessary
    );

  TSetPtkInfo = set of THadeColInfo;

  THadeFieldType = (ftString, ftVarchar, ftChar, ftSmallint, ftInteger, ftBigInt,
    ftBoolean, ftFloat, ftNumeric, ftDateTime, ftTimestamp, ftBlob, ftReference);

  THadeObject = class;
  THadeObjectClass = class of THadeObject;

  { THadeObject }

  THadeObject = class(THadeVisited)
  private
    FOID: THdOID;
    FObjState: THadeObjectState;
    fTableName:String;
  protected
    procedure AssignTo(Dest: THadeVisited); override;
  public
    constructor Create(const AOID: variant=''; const AOwner: THadeVisited=nil); virtual;
    constructor Create(const AOwner: THadeVisited); virtual;

    procedure MarkNew();
    procedure MarkClean();
    procedure MarkDirty();
    procedure MarkDelete();
    procedure MarkPK();
    function objectState: THadeObjectState;

    function findBy(const AConnectionName,APropName: string;
      const AValue: Variant):THadeObject;
    function findBy(const AConnectionName:String;
      Const APropName:Array of String;
      const AValue:Array of Variant):THadeObject;
  published

    property OID: THdOID read FOID write FOID;
  end;

  { THadeObjectList }
  {* we not derrive BOList from BussinesObject like tiOPF do,
     for me it waste memory. BOList not needed OID,ObjectState etc }
  THadeObjectList = class(THadeVisited)
  private
    FList: TFPObjectList;
    //fIndex:integer;
  protected
    function getItem(index: integer): THadeObject; virtual;
    procedure AssignTo(Dest: THadeVisited); override;
  public
    constructor Create(const AOwner: THadeObject = nil);virtual;
    destructor Destroy; override;

    property Items[index: integer]: THadeObject read getItem;

    function add(AObj: THadeObject): integer;
    procedure Clear;
    function Count: integer;

    { the method below not yet implemented, but it would be soon }

    { find Object in the list with criteria }
    function find(const ACriteria:THadeCriteria):THadeObjectList;virtual;

    //navigation
    procedure next;
    procedure prior;
    procedure last;
    procedure first;
  end;

  THadeObjectListClass = class of THadeObjectList;

implementation

uses
  hadertti,
  typinfo,
  hademapping,
  hadesession,
  hadeexception;

{ THadeObject }

procedure THadeObject.AssignTo(Dest: THadeVisited);
var
  List: TStringList;
  iloop: integer;
begin
  if not (Dest.ClassName = Self.ClassName) then
    inherited AssignTo(Dest);

  List := TStringList.Create;
  try
    hadertti.GetPropInfoList(Self, List);

    for iloop := 0 to pred(List.Count) do
    begin
      if hadertti.IsStringProp(Dest, List[iloop]) then
      begin
        hadertti.setStringProp(Dest, List[iloop],
          hadertti.getStringProp(self, List[iloop]));
        continue;
      end;
      if hadertti.IsIntegerProp(Dest, List[iloop]) then
      begin
        hadertti.setIntegerProp(Dest, List[iloop], hadertti.getIntegerProp(
          self, List[iloop]));
        continue;
      end;
      case typinfo.PropType(Self, List[iloop]) of
        tkEnumeration: hadertti.setOrdinalProp(
            Dest, List[iloop], hadertti.getOrdinalProp(self, List[iloop]));
        tkFloat: hadertti.setFloatProp(Dest, List[iloop], hadertti.getFloatProp(
            self, List[iloop]));
        tkClass: AssignTo(THadeObject(hadertti.getHdObjectProp(self,list[iloop])));
        else
          hadertti.setVarProp(Dest, List[iloop], hadertti.getVarProp(self, List[iloop]));
      end;
    end;
  finally
    FreeAndNil(list);
  end;
end;

constructor THadeObject.Create(const AOID: variant; const AOwner: THadeVisited
  );
begin
  FOID := GHadeOID.getOID;
  FOID.setOIDValue(AOID);
  MarkNew;
  RegisterDefaultVisitor;
  if Assigned(AOwner) then
    FOwner := AOwner;
end;

constructor THadeObject.Create(const AOwner: THadeVisited);
begin
  Create(NULL, AOwner);
end;

procedure THadeObject.MarkNew;
begin
  FObjState := posCREATE;
end;

procedure THadeObject.MarkClean;
begin
  FObjState := posCLEAN;
end;

procedure THadeObject.MarkDirty;
begin
  case self.FObjState of
    posEmpty: self.FObjState := posCreate;
    posPK: self.FObjState := posUpdate;
    posCreate: self.FObjState := FObjState; // Do nothing
    posUpdate: self.FObjState := FObjState; // Do nothing
    posDelete: self.FObjState := FObjState; // Do nothing
    posDeleted: self.FObjState := FObjState; // Do nothing
    posClean: self.FObjState := posUpdate;
  end;
end;

procedure THadeObject.MarkDelete;
begin
  FObjState := posDELETE;
end;

procedure THadeObject.MarkPK;
begin
  fObjState:=posPK;
end;

function THadeObject.objectState: THadeObjectState;
begin
  Result := FObjState;
end;

function THadeObject.findBy(const AConnectionName,APropName: string;
  const AValue: Variant): THadeObject;
begin

end;

function THadeObject.findBy(const AConnectionName:String;
  const APropName: array of String;
  const AValue: array of Variant): THadeObject;
begin

end;

{ THadeObjectList }

function THadeObjectList.getItem(index: integer): THadeObject;
begin
  Result := THadeObject(FList.items[index]);
end;

procedure THadeObjectList.AssignTo(Dest: THadeVisited);
begin
  { TODO 1 -oFajar -cOPF : implement THadeObjectList.AssignTo() method }
end;

constructor THadeObjectList.Create(const AOwner: THadeObject);
begin
  FList := TfpObjectList.Create(False);
  RegisterDefaultVisitor;
end;

destructor THadeObjectList.Destroy;
var
  iloop: integer;
begin
  for iloop := 0 to pred(Count) do
  begin
    if THadeObject(flist.items[iloop]).Owner = self then
      THadeObject(flist.items[iloop]).Free;
  end;
  FreeAndNil(FList);
  inherited Destroy;
end;

function THadeObjectList.add(AObj: THadeObject): integer;
begin
  Result := FList.Add(AObj);
end;

procedure THadeObjectList.Clear;
begin
  FList.Clear;
end;

function THadeObjectList.Count: integer;
begin
  Result := FList.Count;
end;

function THadeObjectList.find(const ACriteria: THadeCriteria): THadeObjectList;
begin

end;

procedure THadeObjectList.next;
begin

end;

procedure THadeObjectList.prior;
begin

end;

procedure THadeObjectList.last;
begin

end;

procedure THadeObjectList.first;
begin

end;

end.

